import sparsesvd
import scipy
import csv
from itertools import islice
import numpy as np
import math

e = 0.0001

def recommendation(test_user_id_list, user_like_list, m, n, k, goods_num):

    # row = []
    # col = []
    # data = []
    # for i in range(m):
    #     for j in range(n):
    #         row.append(i)
    #         col.append(j)
    #         data.append(user_like_list[i][j])
    # coo_mat = scipy.sparse.coo_matrix((data, (row, col)), shape=(m, n))
    # csc_mat = coo_mat.tocsc()
    # ut, s, vt = sparsesvd.sparsesvd(csc_mat, k)
    # u = ut.T

    u, c, vt = np.linalg.svd(user_like_list)
    u = u[:,:k]
    vt = vt[:k,:]

    user_recommendation_list = {}
    count = 0
    for user_id in test_user_id_list:
        recommendation_score = {}
        pu = u[user_id]
        pu = np.reshape(pu, [k, 1])
        # 遍历所有物品，依次计算评分
        for i in range(n):
            # i是物品的id
            qit = np.reshape(vt[:, i], [1, k])
            score = np.matmul(qit, pu)[0][0]
            recommendation_score[i] = score

        recommendation_score = sorted(recommendation_score.items(), key=lambda x: x[1], reverse=True)
        topk_recommendation = []
        for id, score in recommendation_score[:goods_num]:
            topk_recommendation.append(id)
        user_recommendation_list[user_id] = topk_recommendation
        if count % 100 == 0:
            print("当前训练进度: {}".format(count / len(test_user_id_list) * 100))
        count += 1
    return user_recommendation_list

def get_max_id(data_path):
    max_user_id = 0
    file = csv.reader(open(data_path, "r", encoding="utf-8"))
    for line in islice(file, 1, None):
        if int(line[0]) > max_user_id:
            max_user_id = int(line[0])
    return max_user_id

def load_train_data(data_path, m, n):
    #生成共现矩阵
    file = csv.reader(open(data_path, "r", encoding="utf-8"))
    user_like_list = np.full((m, n), e, dtype=np.float32)
    for line in islice(file, 1, None):
        user_like_list[int(line[0])][int(line[1])] = 1
    return user_like_list

def load_test_data(data_path):
    file = csv.reader(open(data_path, "r", encoding="utf-8"))
    user_id_list = []
    for line in islice(file, 1, None):
        user_id_list.append(int(line[0]))
    return user_id_list

def write_res_to_csv(user_recommendation_res):
    file = open("submission_svd_2.csv", "w", encoding="utf-8", newline="")
    csv_writer = csv.writer(file)
    csv_writer.writerow(["user_id", "item_id"])

    for user_id, recommendation_list in user_recommendation_res.items():
        for item_id in recommendation_list:
            csv_writer.writerow([str(user_id), str(item_id)])
    file.close()

if __name__ == "__main__":
    train_data_path = "./dataset/book_train_dataset.csv"
    test_data_path = "./dataset/book_test_dataset.csv"
    # n = 10000物品的数量为10000
    # goods_num = 10即用户喜欢物品A，则寻找与物品最相似的 K种物品
    # k为svd分解系数
    # m为用户的数量
    n = 10000
    k = 10
    goods_num = 10
    max_user_id = get_max_id(train_data_path)
    m = max_user_id + 1

    user_like_list = load_train_data(train_data_path, m, n)
    print("训练数据加载完成...")


    test_user_id_list = load_test_data(test_data_path)
    print("测试数据加载完成...")

    user_recommendation_list = recommendation(test_user_id_list, user_like_list, m, n, k, goods_num)
    print("用户物品推荐完成, 正在写入文件...")
    write_res_to_csv(user_recommendation_list)
    print("测试结果写入文件完成！")